/*
 * Leaves Recognition - a neuronal network based recognition of leaf images
 * Copyright (C) 2001 Jens Langner, LightSpeed Communications GbR
 * 
 * Some modifications:
 * Copyright (C) 2010 Oriol Piera, <oriolpiera@gmail.com>
 *
 * LightSpeed Communications GbR
 * Lannerstrasse 1
 * 01219 Dresden
 * Germany
 * http://www.light-speed.de/
 * <Jens.Langner@light-speed.de>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or (at
 * your option) any later version.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 *
 * $Id$
 */

package com.cortsenc.kfulles;


import java.util.ArrayList;

import android.graphics.Bitmap;


public class ImatgeFulla {
	private Bitmap imatge;
	private ArrayList<PuntFulla> punts;
	private int[] pixels;
	public int[] getPixelsInt(){
		return this.pixels;
	}
	private int amp, alc;

	/**
	* Special values for processing Image algorithms
	*/
	// special ColorMask for getting gray pixels
	public static final int PIXEL_MASK = 0x000000ff;

	// Color information
	// Colors are: Alpha(00-ff) Red(00-ff) Green(00-ff) Blue(00-ff)
	// Background color (white)
	private static final int COLOR_BACKGROUND = 0xffffffff;
	// Foreground color (black)
	private static final int COLOR_FOREGROUND = 0xff000000;
	// Color of the skeleton lines
	private static final int COLOR_SKELETON = 0xff0000ff;
	// Color of marking pixels for erase.
	private static final int COLOR_REMOVABLE = 0xff00ffff;
	// Color Line OK (green)
	private static final int COLOR_GOODLINE = 0xff00ff00;
	// Color Line too short (red)
	private static final int COLOR_BADLINE = 0xffff0000;
	// Mark already processed pixels
	private static final int COLOR_DONE = 0xfffffe00;	
	// to recognize a line it have to have this minimum of pixels
	private static int LINE_MIN;
	// Color to mark special points
	private static final int COLOR_POINT_MARK = 0xffff00ff;
	// Color to mark points that we already processed
	private static final int COLOR_POINT_DONE = 0xffffff00;
	// Distance of the special points
	private static int POINT_DIFF;

	// special values for the markPoints() method
	private static long points_pos;
	private static int root_x, root_y;

	
	public ImatgeFulla(int amp, int alc){
		this.amp = amp;
		this.alc = alc;
		this.pixels = new int[alc*amp];
		this.imatge = null;
		this.punts = null;
	}
	public ImatgeFulla(Bitmap bm){
		this.imatge = bm;
		this.punts = null;
		this.amp = bm.getWidth();
		this.alc = bm.getHeight();
		this.pixels = new int[alc*amp];
		this.imatge.getPixels(this.pixels, 0, this.amp, 0, 0, 
										this.amp, this.alc);
	}
	
	
	/**
	  * drawCirlce()
	  *
	  * draw a circle with radius r at the specified position
	  * and with the specified color
	  */
	public void drawCircle(int x, int y, int r, int color){
		for (int i=0; i < 360; i+=5){
			setPixel((int)Math.round(x+Math.sin(i)*r), 
					(int)Math.round(y+Math.cos(i)*r), color);
		}
	}

	/**
	  * drawSquare()
	  *
	  * draw a square with the length of r at a specified position
	  * and with the specified color
	  */
	public void drawSquare(int x, int y, int r, int color){
	    int i;

		for(i=x-(r/2); i<=x+(r/2); i++){
			setPixel(i, y-(r/2), color);
			setPixel(i, y+(r/2), color);
		}

		for(i=y-(r/2); i<=y+(r/2); i++){
			setPixel(x-(r/2), i, color);
			setPixel(x+(r/2), i, color);
		}
	}

	
	
	/**
	  * drawLine()
	  *
	  * draws a line from x0, y0 to x1, y1 with the well-known
	  * Bresenham Algorithm with the specified color.
	  */
	void drawLine(int x0, int y0, int x1, int y1, int color){
	    int ex = x1 - x0;
	    int ey = y1 - y0;
	    int dx, dy, height;

	    if (ex > 0){
	    	dx = 1;
	    }
	    else if (ex < 0){
	    	dx = -1;
	    	ex = -ex;
	    }
	    else{
	    	dx = 0;
	    }

	    if (ey > 0){
	    	dy = 1;
	    }
	    else if (ey < 0){
	    	dy = -1;
	    	ey = -ey;
	    }
	    else{
	    	dy = 0;
	    }

	    int x = x0, y = y0;
	    if (ex > ey){
	    	height = 2*ey -ex;
	    	while(x != x1){
	    		if(height >= 0){
	    			height -= 2*ex;
	    			y += dy;
	    		}
	    		height += 2*ey;
	    		x += dx;
	    		setPixel(x, y, color);
	    	}
	    }
	    else{
	    	height = 2*ex -ey;
	    	while(y != y1){
	    		if(height >= 0){
	    			height -= 2*ey;
	    			x += dx;
	    		}
	    		height += 2*ex;
	    		y += dy;
	    		setPixel(x, y, color);
	    	}
	    }
	}

	
	  /**
	  * edgeDetect()
	  *
	  * method that processes a special edge detection on the whole
	  * array of the Picture.
	  * This edge detection is processed on the gray color amount of the
	  * pixels.
	  *
	  * For the edge detection the "Prewitt" Alogrithm is used:
	  *
	  *     (1 0 -1)          (-1 -1 -1)
	  * 1/3*(1 0 -1)      1/3*( 0  0  0)
	  *     (1 0 -1)          ( 1  1  1)
	  */
	public void edgeDetect(int llindar){
		int x, y;
	    int max=0, min=0;

		// first we create a clear buffer Picture with the
	    // same height & width
		ImatgeFulla Source = new ImatgeFulla(this.amp, this.alc);
	    Source.Clear();

		// Now we process all source pixels of the Array
	    // with the "Prewitt" Algorithm
		for(x=this.amp-2; x > 0; x--){
			for(y=this.alc-2; y > 0; y--){
				int dx  = (getPixelGris(x-1, y+1) + getPixelGris(x, y+1) +
						getPixelGris(x+1, y+1)) - (getPixelGris(x-1, y-1) + 
						getPixelGris(x, y-1) + getPixelGris(x+1, y-1));

				int dy  = (getPixelGris(x+1, y-1) + getPixelGris(x+1, y) + 
						getPixelGris(x+1, y+1)) - (getPixelGris(x-1, y-1) +
						getPixelGris(x-1, y) + getPixelGris(x-1, y+1));

				int z = (int)(Math.sqrt(dx*dx + dy*dy)/3);

				max = z > max ? z : max;
				min = z < min ? z : min;

				// Now we set the pixel of the buffer
				Source.setPixel(x, y, z);
			}
		}

		float a, b;

	    // special values for rescaling the picture
		a = 255f / (max-min);
		b = a * min;

	    // now we copy back every pixel of the buffer to the original
	    // Pixel array
	    for(x=this.amp-1; x >= 0; x--){
	    	for(y=this.alc-1; y >= 0; y--){
	    		setPixel(x, y, (int)(((a*Source.getPixel(x, y)+b) >
	    		llindar ? COLOR_FOREGROUND : COLOR_BACKGROUND)));//If comprimit
	    	}
	    }
	    a = a + 1;
	}
	/*
	  * Clear()
	  *
	  * clear the whole pixel array with white pixels
	  */
	public void Clear(){
		for(int i=0; i < this.alc*this.amp; i++){
			pixels[i] = COLOR_BACKGROUND;
		}
	}
	
	/**
	  * getGrayPixel()
	  *
	  * return the amount of gray color for the specified pixel
	  * in the array.
	  */
	public int getPixelGris(int x, int y){
		if(x < 0){
			x = 0;
		}
		if(y < 0){
			y = 0;
		}
		if(x>= this.amp){
			x = this.amp - 1;
		}
		if(y>= this.alc){
			y = this.alc -1;
		}
				
		return (pixels[y*this.amp+x] & PIXEL_MASK) / 3 +
	      ((pixels[y*this.amp+x] >>  8) & PIXEL_MASK) / 3 +
	      ((pixels[y*this.amp+x] >> 16) & PIXEL_MASK) / 3;
	}
	
	/**
	  * setPixel()
	  *
	  * set the color of a specified pixel in the Array
	  */
	public void setPixel(int x, int y, int color){
		if(x>=0 && y>=0 && x<amp && y<alc){
			pixels[y*amp+x] = color;
		}
	}
	
	/**
	  * getPixel()
	  *
	  * return the color of the specified pixel in the array
	  */
	public int getPixel(int x, int y){
		if(x < 0){
			x = 0;
		}
		if(y < 0){
			y = 0;
		}
		if(x>= this.amp){
			x = this.amp - 1;
		}
		if(y>= this.alc){
			y = this.alc -1;
		}
		
		return pixels[y*this.amp+x];
	}
	
	public Bitmap getImatge(){
		this.imatge.setPixels(this.pixels, 0, this.amp, 0, 0, 
											this.amp, this.alc);
		return Bitmap.createBitmap(this.imatge);
	}
	
	
	/**
	  * thinning()
	  *
	  * Method to process the thinning of a previous edge detected picture.
	  * This algorithm will break down neighbour pixels to a line with one
	  * pixel width
	  */
	public void aprimar(){
		boolean remain;
		int j;
		int x,y;
		remain = true;

		while(remain){
			remain = false;
			for(j=0; j<=6; j+=2){ // j = 0, 2, 4, 6
				for(x=0; x<this.amp; x++){
					  for(y=0; y<this.alc; y++){
						  if(getPixel(x, y) == COLOR_FOREGROUND && 
								  (pixels[vei(x,y,j)] == COLOR_BACKGROUND)){
							  if(matchPatterns(x,y)){
								  // set Pixel with special SKELETON color
								  setPixel(x, y, COLOR_SKELETON);  
							  }
							  else{
								  // set Pixel as a REMOVABLE pixel
								  setPixel(x, y, COLOR_REMOVABLE);  
								  remain = true;
							  }
						  }
					  }
				  }

			  	// Now we process the pixel array and change (remove)
				// pixels that were previously marked as REMOVABLE
				for(x=0; x<this.amp; x++){
					for(y=0; y<this.alc; y++){
						if(getPixel(x, y) == COLOR_REMOVABLE){
							setPixel(x, y, COLOR_BACKGROUND);
						}
					}
				}
			}
		}
	}
	
	  /*
	  * neighbour()
	  *
	  * special method that returns the offset of a neighbour
	  * pixel to x,y in the specified direction j
	  *
	  */
	private int vei(int x, int y, int j){
		switch(j){
			case 0:	x++; break;
			case 1:	x++; y--;	break;
			case 2:	y--; break;
			case 3:	x--; y--;	break;
			case 4:	x--; break;
			case 5:	x--; y++;	break;
			case 6:	y++; break;
			case 7:	x++; y++;	break;
		}

		if(x>=this.amp-1){
			x = this.amp-1;
		}
		if(x<0){
			x = 0;
		}
		if(y>=this.alc-1){
			y = this.alc-1;
		}
		if(y<0){
			y = 0;
		}

		return y*this.amp+x;
	}

	  /**
	  * matchPatterns()
	  *
	  * special method that checks if a specified pattern
	  * matches the actual position x,y of the array.
	  * this method is mainly used by the thinning() algorithm
	  */
	private boolean matchPatterns(int x, int y){
		if(x>=this.amp-1){
			x = this.amp-1;
		}
		if(x<0){
			x = 0;
		}
		if(y>=this.alc-1){
			y = this.alc-1;
		}
		if(y<0){
			y = 0;
		}

		if(pixels[vei(x,y,0)] == COLOR_BACKGROUND &&
			 pixels[vei(x,y,4)] == COLOR_BACKGROUND &&
			(pixels[vei(x,y,1)] != COLOR_BACKGROUND ||		// A A A
			 pixels[vei(x,y,2)] != COLOR_BACKGROUND ||		// 0 P 0
			 pixels[vei(x,y,3)] != COLOR_BACKGROUND)&&		// B B B
			(pixels[vei(x,y,5)] != COLOR_BACKGROUND ||
			 pixels[vei(x,y,6)] != COLOR_BACKGROUND ||
			 pixels[vei(x,y,7)] != COLOR_BACKGROUND )){
			return true;
		}
	    else if(pixels[vei(x,y,2)] == COLOR_BACKGROUND &&
				pixels[vei(x,y,6)] == COLOR_BACKGROUND &&
				(pixels[vei(x,y,7)] != COLOR_BACKGROUND ||	// B 0 A
				pixels[vei(x,y,0)] != COLOR_BACKGROUND ||	// B P A
				pixels[vei(x,y,1)] != COLOR_BACKGROUND)&&	// B 0 A
				(pixels[vei(x,y,3)] != COLOR_BACKGROUND ||
				pixels[vei(x,y,4)] != COLOR_BACKGROUND ||
				pixels[vei(x,y,5)] != COLOR_BACKGROUND )){
			return true;
		}
	    else if (pixels[vei(x,y,7)] == COLOR_SKELETON &&
				 pixels[vei(x,y,0)] == COLOR_BACKGROUND &&
				 pixels[vei(x,y,6)] == COLOR_BACKGROUND &&
				 (pixels[vei(x,y,1)] != COLOR_BACKGROUND ||	// A A A
				 pixels[vei(x,y,2)] != COLOR_BACKGROUND ||	// A P 0
				 pixels[vei(x,y,3)] != COLOR_BACKGROUND ||	// A 0 2
				 pixels[vei(x,y,4)] != COLOR_BACKGROUND ||
				 pixels[vei(x,y,5)] != COLOR_BACKGROUND )){
			return true;
		}
	    else if (pixels[vei(x,y,5)] == COLOR_SKELETON &&
				pixels[vei(x,y,4)] == COLOR_BACKGROUND &&
				pixels[vei(x,y,6)] == COLOR_BACKGROUND &&
				(pixels[vei(x,y,7)] != COLOR_BACKGROUND ||	// A A A
				pixels[vei(x,y,0)] != COLOR_BACKGROUND ||	// 0 P A
				pixels[vei(x,y,1)] != COLOR_BACKGROUND ||	// 2 0 A
				pixels[vei(x,y,2)] != COLOR_BACKGROUND ||
				pixels[vei(x,y,3)] != COLOR_BACKGROUND )){
			return true;
		}
	    else if (pixels[vei(x,y,3)] == COLOR_SKELETON &&
				pixels[vei(x,y,2)] == COLOR_BACKGROUND &&
				pixels[vei(x,y,4)] == COLOR_BACKGROUND &&
				(pixels[vei(x,y,5)] != COLOR_BACKGROUND ||	// 2 0 A
				pixels[vei(x,y,6)] != COLOR_BACKGROUND ||	// 0 P A
				pixels[vei(x,y,7)] != COLOR_BACKGROUND ||	// A A A
				pixels[vei(x,y,0)] != COLOR_BACKGROUND ||
				pixels[vei(x,y,1)] != COLOR_BACKGROUND )){
			return true;
		}
	    else if (pixels[vei(x,y,1)] == COLOR_SKELETON &&
				pixels[vei(x,y,0)] == COLOR_BACKGROUND &&
				pixels[vei(x,y,2)] == COLOR_BACKGROUND &&
				(pixels[vei(x,y,3)] != COLOR_BACKGROUND ||	// A 0 2
				pixels[vei(x,y,4)] != COLOR_BACKGROUND ||	// A P 0
				pixels[vei(x,y,5)] != COLOR_BACKGROUND ||	// A A A
				pixels[vei(x,y,6)] != COLOR_BACKGROUND ||
				pixels[vei(x,y,7)] != COLOR_BACKGROUND )){
			return true;
		}
	    else{
			return false;
		}
	}
	
	
	  /**
	  * checkLines()
	  *
	  * Method that checks every pixel of the array if it is a skeleton
	  * pixel and then start the line checking algorithm to filer out too
	  * short lines which are really no line at all.
	  */
	public void checkLines(int minLine){
		int x, y;
		int length = 0;

	    LINE_MIN = minLine;
	    
		for(y=0; y<this.alc; y++){
			for(x=0; x<this.amp; x++){
				if(getPixel(x, y) == COLOR_SKELETON){
					length = checkLineLength(x, y, 1);
					if (length > LINE_MIN){
						paintLines(x, y, COLOR_GOODLINE);
					}
					else{
						paintLines(x, y, COLOR_BADLINE);
					}
					length = 0;
				}
			}
	    }
	}

	  /**
	  * checkLineLength()
	  *
	  * checks the length of skeleton lines. The actual pixel will be
	  * marked as processed and then the length of the line will be incremented
	  * until the line ends.
	  */
	private int checkLineLength(int x, int y, int length){
	    // we mark this pixel as "processed"
		setPixel(x, y, COLOR_DONE);
		if(length<50){ //Modificació per tallar la recursivitat
			try{
				if(pixels[vei(x, y, 0)] == COLOR_SKELETON){
					length = checkLineLength(x+1, y, length+1);
				}
				if(pixels[vei(x, y, 1)] == COLOR_SKELETON){
					length = checkLineLength(x+1, y-1, length+1);
				}
				if(pixels[vei(x, y, 2)] == COLOR_SKELETON){
					length = checkLineLength(x, y-1, length+1);
				}
				if(pixels[vei(x, y, 3)] == COLOR_SKELETON){
					length = checkLineLength(x-1, y-1, length+1);
				}
				if(pixels[vei(x, y, 4)] == COLOR_SKELETON){
					length = checkLineLength(x-1, y, length+1);
				}
				if(pixels[vei(x, y, 5)] == COLOR_SKELETON){
					length = checkLineLength(x-1, y+1, length+1);
				}
				if(pixels[vei(x, y, 6)] == COLOR_SKELETON){
					length = checkLineLength(x, y+1, length+1);
				}
				if(pixels[vei(x, y, 7)] == COLOR_SKELETON){
					length = checkLineLength(x+1, y+1, length+1);
				}
			}
		    catch(Exception e){
		    	System.out.println("Maybe Stackoverflow!!\n"+e);
			}
		}
		return length;
	}

	  /**
	  * paintLines()
	  *
	  * special method that processes to a specified beginning of
	  * a line and then change the color to the specified one.
	  */
	private void paintLines(int x, int y, int color){
		setPixel(x, y, color);

		try{
			if(pixels[vei(x, y, 0)] == COLOR_DONE){
				paintLines(x+1,  y,    color);
			}
			if(pixels[vei(x, y, 1)] == COLOR_DONE){
				paintLines(x+1,  y-1,  color);
			}
			if(pixels[vei(x, y, 2)] == COLOR_DONE){
				paintLines(x,    y-1,  color);
			}
			if(pixels[vei(x, y, 3)] == COLOR_DONE){
				paintLines(x-1,  y-1,  color);
			}
			if(pixels[vei(x, y, 4)] == COLOR_DONE){
				paintLines(x-1,  y,    color);
			}
			if(pixels[vei(x, y, 5)] == COLOR_DONE){
				paintLines(x-1,  y+1,  color);
			}
			if(pixels[vei(x, y, 6)] == COLOR_DONE){
				paintLines(x,    y+1,  color);
			}
			if(pixels[vei(x, y, 7)] == COLOR_DONE){
				paintLines(x+1,  y+1,  color);
			}
		}
	    catch(Exception e){
			System.out.println("Maybe Stackoverflow\n"+e);
		}
	}

	  /**
	  * markPoints()
	  *
	  * method to process the thinned lines and mark every POINT_DIFFth pixel
	  * and write this in a special Node object to calculate the cosinus
	  * direction later
	  */
	public void markPoints(int distance){
		int x, y;
		boolean trobat;
	    POINT_DIFF = distance;
	    points_pos = POINT_DIFF-1;

		for(y=0; y<this.alc; y++){
			for(x=0; x<this.amp; x++){
				trobat = true;
				if(getPixel(x, y) == COLOR_GOODLINE){
					PuntFulla pf = new PuntFulla(x, y);
					while(trobat){
						trobat = paintPoints(pf.getX1(), pf.getY1());
					}
 				}
			}
	    }
	}

	  /**
	  * paintPoints()
	  *
	  * special method to process through a thinned line and mark every
	  * pixel with a distance of POINT_DIFF
	  */
	private boolean paintPoints(int x, int y){
		boolean result = false;

	    // increment this global variable first
	    points_pos++;

	    // if the distance is POINT_DIFF we mark this point !
	    if(points_pos == POINT_DIFF){
	    	setPixel(x, y, COLOR_POINT_MARK);
	    	points_pos = 0;
	    	return false;
	    }
	    else{
	    	setPixel(x, y, COLOR_POINT_DONE);
			try{
				if(pixels[vei(x, y, 0)] == COLOR_GOODLINE){
					result = paintPoints(x+1,  y  );
				}
				if(pixels[vei(x, y, 1)] == COLOR_GOODLINE){ 
					result = paintPoints(x+1,  y-1);
				}
				if(pixels[vei(x, y, 2)] == COLOR_GOODLINE){ 
					result = paintPoints(x,    y-1);
				}
				if(pixels[vei(x, y, 3)] == COLOR_GOODLINE){ 
					result = paintPoints(x-1,  y-1);
				}
				if(pixels[vei(x, y, 4)] == COLOR_GOODLINE){ 
					result = paintPoints(x-1,  y  );
				}
				if(pixels[vei(x, y, 5)] == COLOR_GOODLINE){ 
					result = paintPoints(x-1,  y+1);
				}
				if(pixels[vei(x, y, 6)] == COLOR_GOODLINE){ 
					result = paintPoints(x,    y+1);
				}
				if(pixels[vei(x, y, 7)] == COLOR_GOODLINE){ 
					result = paintPoints(x+1,  y+1);
				}
			}
		    catch(Exception e){
		    	System.out.println("Maybe Stackoverflow\n"+e);
			}
	    }
	    return true;
	}


	  /**
	  * calcAngels()
	  *
	  * method to process the whole image and search for the marked points
	  * and then find the next points that are connected to this points.
	  */
	public void calcAngels(){
		int x, y;
	    root_x = root_y = -1;

	    // create a new ArrayList to count the tokens
	    punts = new ArrayList<PuntFulla>();

		for(y=0; y<this.alc; y++){
			for(x=0; x<this.amp; x++){
				if(getPixel(x, y) == COLOR_POINT_MARK){
	    			searchNeighbour(x, y, true);
	 			}
			}
	    }

	    for(int i=0; i < punts.size(); i++){
	    	PuntFulla actToken = (PuntFulla)punts.get(i);
	    	drawSquare(actToken.getX1(), actToken.getY1(), 5, COLOR_BADLINE);
	    }
	}

	  /**
	  * searchNeighbour()
	  *
	  * special method that search for neighbour pixels with COLOR_POINT_MARK
	  * that are connected through a COLOR_POINT_DONE line.
	  * then we draw a direct line through this two points.
	  */
	private void searchNeighbour(int x, int y, boolean isRoot){
		if(getPixel(x, y) == COLOR_POINT_MARK){
			if(isRoot == true){
				root_x = x;
				root_y = y;
			}
			else if(isRoot == false &&
	              root_x != -1 && root_y != -1){
				// if root and the actual is the same or only one pixel away
				// we skip this action.
				if((root_x+root_y)-(x+y) == 0){
					return;
				}
				
				drawLine(root_x, root_y, x, y, COLOR_SKELETON);

				// now we create a new token for this line and add it to the
				// ArrayList
				PuntFulla ltoken = new PuntFulla(root_x, root_y, x, y);
				punts.add(ltoken);

				setPixel(root_x, root_y, COLOR_POINT_MARK);
				setPixel(x, y, COLOR_POINT_MARK);

				return;
			}
	    }
	    else{
	    	setPixel(x, y, COLOR_GOODLINE);
	    }

		try{
			if( pixels[vei(x, y, 0)] == COLOR_POINT_DONE ||
					pixels[vei(x, y, 0)] == COLOR_POINT_MARK){ 
				searchNeighbour(x+1,  y  , false);
			}
			if( pixels[vei(x, y, 1)] == COLOR_POINT_DONE ||
					pixels[vei(x, y, 1)] == COLOR_POINT_MARK){ 
				searchNeighbour(x+1,  y-1, false);
			}
			if( pixels[vei(x, y, 2)] == COLOR_POINT_DONE ||
					pixels[vei(x, y, 2)] == COLOR_POINT_MARK){ 
				searchNeighbour(x,    y-1, false);
			}
			if( pixels[vei(x, y, 3)] == COLOR_POINT_DONE ||
					pixels[vei(x, y, 3)] == COLOR_POINT_MARK){ 
				searchNeighbour(x-1,  y-1, false);
			}
			if( pixels[vei(x, y, 4)] == COLOR_POINT_DONE ||
					pixels[vei(x, y, 4)] == COLOR_POINT_MARK){ 
				searchNeighbour(x-1,  y  , false);
			}
			if( pixels[vei(x, y, 5)] == COLOR_POINT_DONE ||
					pixels[vei(x, y, 5)] == COLOR_POINT_MARK){ 
				searchNeighbour(x-1,  y+1, false);
			}
			if( pixels[vei(x, y, 6)] == COLOR_POINT_DONE ||
					pixels[vei(x, y, 6)] == COLOR_POINT_MARK){ 
				searchNeighbour(x,    y+1, false);
			}
			if( pixels[vei(x, y, 7)] == COLOR_POINT_DONE ||
					pixels[vei(x, y, 7)] == COLOR_POINT_MARK){ 
				searchNeighbour(x+1,  y+1, false);
			}
		}
	    catch(Exception e){
			System.out.println("Maybe Stackoverflow\n"+e);
		}

	    if(isRoot == true){
	    	setPixel(x, y, COLOR_SKELETON);
	    }
	}

	  /**
	  * getTokens()
	  *
	  * special method that returns a reference to the recognized
	  * TokenArray that was calculated after the calcAngels()
	  */
	  public ArrayList<PuntFulla> getTokens(){
		  return punts;
	  }
}